#define STB_IMAGE_IMPLEMENTATION
#include "include/stb_image.h"
#include "math.h"

#include <stdio.h>

#define NO_FILE_NAME 0x0a
#define VALID_ARG    0x0b

const char transition[] = {
        '`', '.', '_', '~',
        '^', '=', '?', '/',
        '(', '[', 'C', 'X',
        'E', 'O', '$', '#',
        'W', '@',
};

void process_img(const stbi_uc *data, int height, int width, int n, int size) {
    int p_len_w = size;
    int p_len_h = ceil(1.8 * p_len_w);
    if (n == 1) {
        int step;
        step = width;
        for (int h = 0; h < height; h += p_len_h) {
            for (int w = 0; w < width; w += p_len_w) {
                // |<- 10 ->|
                // o ------ o --
                // |        |  .
                // |        |  .
                // o ------ o --
                int start_h = h;
                int start_w = w;
                int end_h = h + p_len_h;
                int end_w = w + p_len_w;

                end_h = end_h > height ? height : end_h;
                end_w = end_w > width  ? width  : end_w;

                int p_sum = 0;
                int cnt = 0;
                for (int ch = start_h; ch < end_h; ch++) {
                    for (int cw = start_w; cw < end_w; cw++) {
                        stbi_uc  p_val = data[cw + ch * step];
                        p_sum += p_val;
                        cnt++;
                    }
                }
                int avg_p = p_sum / cnt;
                putchar(transition[avg_p / 15]);
            }
            putchar('\n');
        }
    } else if (n == 3 || n == 4) {
        int step;
        step = width * n;
        int sum_cnt = 0;
        for (int h = 0; h < height; h += p_len_h) {
            for (int w = 0; w < width; w += p_len_w) {
                // |<- 10 ->|
                // o ------ o --
                // |        |  .
                // |        |  .
                // o ------ o --
                int start_h = h;
                int start_w = w;
                int end_h = h + p_len_h;
                int end_w = w + p_len_w;

                end_h = end_h > height ? height : end_h;
                end_w = end_w > width  ? width  : end_w;

                int p_sum = 0;
                int cnt = 0;
                for (int ch = start_h; ch < end_h; ch++) {
                    for (int cw = start_w; cw < end_w; cw++) {
                        stbi_uc  p_val_r = data[cw * n + ch * step + 0];
                        stbi_uc  p_val_g = data[cw * n + ch * step + 1];
                        stbi_uc  p_val_b = data[cw * n + ch * step + 2];
                        p_sum += (p_val_r + p_val_g + p_val_b) / 3;
                        cnt++;
                    }
                }
                int avg_p = p_sum / cnt;
                putchar(transition[avg_p / 15]);
                sum_cnt ++;
            }
            putchar('\n');
        }
        printf("sum_cnt = %d", sum_cnt);
    }
}

int main(int arg_num, char* args[]) {
    if (arg_num <= 1) {
        puts("Please input a filename.");
        exit(NO_FILE_NAME);
    }
    if (arg_num == 2) {
        const char *filename = args[1];

        int height, width, channels;
        stbi_uc *data = stbi_load(filename, &width, &height, &channels, 0);

        int size = width / 300;
        size = size == 0 ? 1 : size;
        process_img(data, height, width, channels, size);

        stbi_image_free(data);
    } else if (arg_num == 3) {
        const char *filename = args[1];
        const int size = atoi(args[2]);

        if (size <= 0) {
            printf("Please input a arg > 0.");
            exit(VALID_ARG);
        }

        int height, width, channels;
        stbi_uc *data = stbi_load(filename, &width, &height, &channels, 0);

        process_img(data, height, width, channels, size);

        stbi_image_free(data);
    }
    return 0;
}